
#include <common.h>
#include <devnode.h>
#include <tpunb.h>
#include <mqtt_client.h>
#include <input_event.h>
#include <server.h>
#include <system.h>
#include <sys/types.h>			/* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <time.h>
#include <recordModule.h>
#include <firmware.h>

static int water_level_1	= WATER_LEVEL_1;
static int water_level_2	= WATER_LEVEL_2;
static int water_level_3	= WATER_LEVEL_3;	//3级水位值报警
static int alarm_interval	= ALARM_INTERVAL;	//报警间隔

int get_water_level_1(void)
{
	return water_level_1;
}

int get_water_level_2(void)
{
	return water_level_2;
}

int get_water_level_3(void)
{
	return water_level_3;
}

int get_alarm_interval(void)
{
	return alarm_interval;
}

void water_alarm_info_parse(char *filename)
{
	cJSON *root;
	cJSON *value;

	root = parse_root_from_file(filename);
	if(root) {
		value = cJSON_GetObjectItem(root, "waterLevel_1");
		if(value) {
			water_level_1 = value->valueint;
		}
		
		value = cJSON_GetObjectItem(root, "waterLevel_2");
		if(value) {
			water_level_2 = value->valueint;
		}

		value = cJSON_GetObjectItem(root, "waterLevel_3");
		if(value) {
			water_level_3 = value->valueint;
		}

		value = cJSON_GetObjectItem(root, "alarm_interval");
		if(value) {
			alarm_interval = value->valueint;
		}

		warn_water_notify_qt(water_level_1, water_level_2, water_level_3);
	}

}

/*	+++++	终端链表		+++++	*/

#define	LOOP_WAIT_TIMEOUT			10000	//10秒
#define	WARN_WAIT_ANSWER_TIMEOUT	30000	//30秒

#define RETRY_COUNT					5

//static struct list_head dev_node_list_head;
//static LIST_HEAD(dev_node_list_head);
struct list_head dev_node_list_head = LIST_HEAD_INIT(dev_node_list_head);

static struct list_head *get_devnode_list_head(void)
{
	return &dev_node_list_head;
}

static int devnode_list_empty(void)
{
	return list_empty(&dev_node_list_head);
}

DEV_NODE *get_dev_node(char *dev_sn)
{
	DEV_NODE *dev_node, *tmp;
	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
		if(strncmp(dev_node->dev_sn, dev_sn, sizeof(dev_node->dev_sn)) == 0) {
			return dev_node;
		}
	}

	return NULL;
}

DEV_NODE *get_dev_node_by_addr(unsigned short addr)
{
	DEV_NODE *dev_node, *tmp;
	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
		if(dev_node->devaddr == addr) {
			return dev_node;
		}
	}

	return NULL;
}


void dev_node_init(void)
{
	INIT_LIST_HEAD(&dev_node_list_head);
}

static void dev_addr_save_to_file(char *dev_sn, unsigned short dev_addr)
{
	cJSON *root;
	cJSON *dev_array;
	cJSON *element;
	cJSON *devSn;
	cJSON *nodeAddr;

	int index;
	int dev_count;

	char addr_str[32] = {0};

	root = parse_root_from_file(DEV_NODE_FILE);
	if(root) {
		dev_array = cJSON_GetObjectItem(root, "data");
		if(dev_array == NULL)
			return;
		
		dev_count = cJSON_GetArraySize(dev_array);
		for(index=0; index<dev_count; index++) {
			element = cJSON_GetArrayItem(dev_array, index);
			devSn = cJSON_GetObjectItem(element, "devSn");
			if(strcmp(dev_sn, devSn->valuestring) == 0) {
				sprintf(addr_str, "%04X", dev_addr);
				nodeAddr = cJSON_GetObjectItem(element, "devAddr");
				if(nodeAddr == NULL) {
					//添加地址
					cJSON_AddStringToObject(element, "devAddr", addr_str);
				} else {
					//修改地址
					cJSON_ReplaceItemInObject(element, "devAddr", cJSON_CreateString(addr_str));
				}				
				break;
			}
		}
		
		save_root_to_file(root, DEV_NODE_FILE);
		cJSON_Delete(root);
	}

}

/**** ++++++ 报警相关     ++++++ ****/

//报警信息
static WARN_STATE_E g_warn_req;			//报警请求 	   4-消警	3-注意安全 2-准备转移 1-立即转移
static WARN_STATE_E g_warn_value;		//报警值
static unsigned int g_warn_time;		//报警时间
static unsigned int g_warn_seq;			//指令序列号		用于去重
static unsigned int g_cancel_time;		//消警时间

static pthread_t warn_threadid = 0;
static int is_scan_warn_need_stop = 0;	//1：线程需停止

void gw_alarm_to_server(int alarm_level, double water_level)
{
	char *out;
	cJSON *root;
	root = cJSON_Create("alarm");
	cJSON_AddNumberToObject(root, "alarm_level", alarm_level);
	if(water_level >= 0) cJSON_AddNumberToObject(root, "water_level", water_level);
	out = cJSON_PrintUnformatted(root);
	cJSON_Delete(root);
	gw_publish_notify_req_data(out, strlen(out));
	free(out);
}

void update_all_devnode_warn(unsigned short warn_rsp_state)
{
	DEV_NODE *dev_node, *tmp;
	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
		dev_node->warn_rsp_state = warn_rsp_state;
		dev_node->warn_rsp_time = 0;
		dev_node->answer_rsp_time = 0;
	}
}

void update_all_devnode_cancel(unsigned short cancel_rsp_state)
{
	DEV_NODE *dev_node, *tmp;
	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
		dev_node->cancel_rsp_state = cancel_rsp_state;
		dev_node->cancel_rsp_time = 0;
	}
}

static int is_warn_thread_active(void)
{
	return (is_scan_warn_need_stop == 0);
}

static int get_online_dev_num(void)
{
	int num = 0;
	
	DEV_NODE *dev_node, *tmp;
	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
		if(dev_node->online == 1) {
			++num;	//统计在线终端
		}
	}

	return num;
}

//报警广播
static void warn_broadcast(WARN_STATE_E warn_value, int seq)
{
	unsigned char buf[128] = {0};
	WARN_REQ_DATA *warn_req = (WARN_REQ_DATA *)buf;

	warn_req->warn_status = warn_value;
	if(seq <= 0) {
		warn_req->warn_seq = generate_msgid();
	} else {
		warn_req->warn_seq = seq;
	}

	hydrology_transform(HYD_CMD_WARN, (unsigned char *)(warn_req), sizeof(WARN_REQ_DATA));
}

//报警点播
static void warn_unicast(DEV_NODE *dev_node, WARN_STATE_E warn_value, int seq)
{
	char to_devsn[32] = {0};
	unsigned char buf[128] = {0};
	WARN_REQ_DATA *warn_req = (WARN_REQ_DATA *)buf;
	hydrology_param_t hydrology_param;

	//指令增加报警器SN,防止广播时同时回复
	sn_convert(to_devsn, dev_node->dev_sn);
	sn_to_devid(to_devsn, warn_req->remoter_addr);

	warn_req->warn_status = warn_value;
	if(seq <= 0) {
		warn_req->warn_seq = generate_msgid();
	} else {
		warn_req->warn_seq = seq;
	}

	memset(&hydrology_param, 0, sizeof(hydrology_param));
	hydrology_param.cmdtype = HYD_CMD_WARN;
	hydrology_param.buf = (unsigned char *)(warn_req);
	hydrology_param.length = sizeof(WARN_REQ_DATA);
	hydrology_param.addr = dev_node->devaddr;
	memcpy(hydrology_param.dev_sn, dev_node->dev_sn, sizeof(dev_node->dev_sn));
	hydrology_transform_enqueue(&hydrology_param);	//devaddr > 0 点播,	devaddr == 0 广播
}

//报警点播
void warn_unicast_of_devSn(char *dev_sn, WARN_STATE_E warn_value)
{
	DEV_NODE *dev_node;
	
	dev_node = get_dev_node(dev_sn);
	if(dev_node) {
		warn_unicast(dev_node, warn_value, 0);
	}
}

void dev_warn_notify(char *dev_sn, int warn_level)
{
	DEV_NODE *dev_node;

	if(dev_sn == NULL) {
		//报警广播
		warn_broadcast(warn_level, 0);
	} else {
		//报警点播
		dev_node = get_dev_node(dev_sn);
		if(dev_node) {
			warn_unicast(dev_node, warn_level, 0);
		}
	}
}

void dev_warn_cancel_notify(char *dev_sn)
{
	DEV_NODE *dev_node;

	if(dev_sn == NULL) {
		//消警广播
		warn_broadcast(ALARM_STATE_Cancel_transfer, 0);
	} else {
		//消警点播
		dev_node = get_dev_node(dev_sn);
		if(dev_node) {
			warn_unicast(dev_node, ALARM_STATE_Cancel_transfer, 0);
		}
	}
}

static int get_no_answer_dev_num(void)
{
	int num = 0;
	DEV_NODE *dev_node, *tmp;	
	
	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
		if(is_warn_thread_active() && dev_node->online == 1 && dev_node->warn_rsp_state == 2) {//loop_1
			++num;
		}
	}

	return num;
}

//判断是消警流程
static int is_warn_cancel_process(void)
{
	return (g_warn_req == ALARM_STATE_Cancel_transfer);
}

static void warn_thread_interruptable_waiting(int count)
{
	int i = 0;
	while(is_warn_thread_active() && i < count) {
		++i;
		//second_sleep(1);
		millisecond_sleep(1);
	}
}

static void warn_rsp_status_handle(void)
{
	int i;
	DEV_NODE *dev_node, *tmp;	

	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
		if(is_warn_thread_active() && dev_node->online == 1 && dev_node->warn_rsp_state == 1) {//loop_1
			//尝试点播5次
			for(i = 0; is_warn_thread_active() && (i < RETRY_COUNT); i++) {//loop_2
				//如果设备指令未回复,发送点播指令
				warn_unicast(dev_node, g_warn_req, g_warn_seq);

				//每次等待10秒
				warn_thread_interruptable_waiting(LOOP_WAIT_TIMEOUT);

				if(dev_node->warn_rsp_state != 1)	//已回复或已应答
					break;
			}
		}
	}
}

//对在线设备点播消警指令
static void warn_cancel_status_handle(void)
{
	int i;
	DEV_NODE *dev_node, *tmp;	

	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
		if(is_warn_thread_active() && dev_node->online == 1 && dev_node->cancel_rsp_state == 1) {//loop_1
			//尝试点播5次
			for(i = 0; is_warn_thread_active() && (i < RETRY_COUNT); i++) {//loop_2
				//如果设备指令未回复,发送点播指令
				warn_unicast(dev_node, g_warn_req, g_warn_seq);

				//每次等待10秒
				warn_thread_interruptable_waiting(LOOP_WAIT_TIMEOUT);

				if(dev_node->cancel_rsp_state == 2)	//已回复或已应答
					break;
			}
		}
	}
}

//用消警指令点播离线设备,用于获取离线设备的在线情况
static void warn_cancel_offline_device(void)
{
	int i;
	DEV_NODE *dev_node, *tmp;	

	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
		if(is_warn_thread_active() && dev_node->online == 0) {//loop_1
			//尝试点播5次
			for(i = 0; is_warn_thread_active() && (i < RETRY_COUNT); i++) {//loop_2
				//如果设备指令未回复,发送点播指令
				warn_unicast(dev_node, g_warn_req, g_warn_seq);

				//每次等待10秒
				warn_thread_interruptable_waiting(LOOP_WAIT_TIMEOUT);

				if(dev_node->online == 1) //已回复或已应答
					break;
			}
		}
	}
}


static void warn_answer_status_handle(void)
{
	int i;
	DEV_NODE *dev_node, *tmp;	

	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
		if(is_warn_thread_active() && dev_node->online == 1 && dev_node->warn_rsp_state == 2) {//loop_1
	
			for(i = 0; is_warn_thread_active() && (i < RETRY_COUNT); i++) {//loop_2
				//如果设备指令未回复,发送点播指令
				warn_unicast(dev_node, g_warn_req, g_warn_seq);
	
				//每次等待10秒
				warn_thread_interruptable_waiting(LOOP_WAIT_TIMEOUT);

				if(dev_node->warn_rsp_state == 3)	//已应答
					break;
			}
		}
	}
}

//报警叫应记录
static void warn_record_result_handle(void)
{
	char *out;
	DEV_NODE *dev_node, *tmp;
	cJSON *root, *data, *element;
	char file_name[256] = {0};

	sprintf(file_name, "%s/warn_record_%d.json", WARN_RECORD_PATH, g_warn_time);

	if(g_warn_time == 0)
		return;

	root = cJSON_Create("warn_record");
	if(root) {
		cJSON_AddNumberToObject(root, "warn_val", g_warn_value);
		cJSON_AddNumberToObject(root, "warn_time", g_warn_time);
		cJSON_AddItemToObject(root, "data", data = cJSON_CreateArray());
		list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
			if(dev_node->online == 0)
				continue;
			
			element = cJSON_CreateObject();
			cJSON_AddStringToObject(element, "devSn", dev_node->dev_sn);
			cJSON_AddNumberToObject(element, "online", dev_node->online);
			cJSON_AddNumberToObject(element, "warn_rsp_time", dev_node->warn_rsp_time);
			cJSON_AddNumberToObject(element, "answer_rsp_time", dev_node->answer_rsp_time);
			cJSON_AddItemToArray(data, element);
		}
		save_root_to_file(root, file_name);
		out = cJSON_PrintUnformatted(root);
		cJSON_Delete(root);
		gw_publish_notify_req_data(out, strlen(out));
		free(out);
	}

	g_warn_time = 0;
}

static void devNode_publish_all_offline_to_server(void)
{
	char *out;
	cJSON *root, *data, *element;
	DEV_NODE *dev_node, *tmp;

	char addr_str[32] = {0};

	root = cJSON_Create("status");
	cJSON_AddItemToObject(root, "data", data = cJSON_CreateArray());
	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
		if(dev_node->online == 0) {
			sprintf(addr_str, "%04X", dev_node->devaddr);
			element = cJSON_CreateObject();
			cJSON_AddStringToObject(element, "devSn", dev_node->dev_sn);
			//cJSON_AddStringToObject(element, "devAddr", addr_str);
			cJSON_AddNumberToObject(element, "online", dev_node->online);
			//cJSON_AddNumberToObject(element, "battery", dev_node->battery_level);
			//cJSON_AddNumberToObject(element, "rssi", dev_node->dev_rssi);
			cJSON_AddItemToArray(data, element);
		}
	}

	out = cJSON_PrintUnformatted(root);
	cJSON_Delete(root);
	gw_publish_notify_req_data(out, strlen(out));
	free(out);
}

static void cancel_rsp_status_handle(void)
{
	int offline_update = 0;
	DEV_NODE *dev_node, *tmp;	

	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
		if(dev_node->online == 1 && dev_node->cancel_rsp_state == 1) {
			//更新UI为离线状态
			online_state_notify_qt(dev_node->dev_sn, 3);

			//设备可能已经离线
			dev_node->online = 0;

			//有设备离线需上报平台标志
			offline_update = 1;
		}
	}

	if(offline_update) {
		devNode_publish_all_offline_to_server();
	} 
}


static void *scan_warn_thread(void *arg)
{
	//报警 消警分开处理
	//DEBUG("warn thread start");

	if(is_warn_cancel_process()) {
		update_all_devnode_cancel(1);	//设为 1:消警状态未回复
	} else {
		update_all_devnode_warn(1);		//设为 1:报警状态未回复
	}

	//广播一条报警或消警请求
	warn_broadcast(g_warn_req, g_warn_seq);

	//判断是消警流程
	if(is_warn_cancel_process()) {
		//报警,保存叫应记录,并推送平台
		warn_record_result_handle();
	}

	//报警线程可中断等待10秒
	warn_thread_interruptable_waiting(LOOP_WAIT_TIMEOUT);

	//没有在线的终端,直接退出
	if(get_online_dev_num() == 0) {
		goto exit_warn;
	}

	if(is_warn_cancel_process()) {
		//对在线设备点播消警指令
		warn_cancel_status_handle();
	} else {
		//查询报警回复
		warn_rsp_status_handle();
		
		//有在线未应答查询
		if(get_no_answer_dev_num() > 0) {
			//等待3分钟
			warn_thread_interruptable_waiting(WARN_WAIT_ANSWER_TIMEOUT);

			//查询报警应答
			warn_answer_status_handle();
		}
	}

	if(is_warn_thread_active()) {

		//保存叫应记录:报警回复,应答,消警
		if(is_warn_cancel_process()) {
			//对在线,消警指令没有回复的处理,将其置为离线,并上报平台
			cancel_rsp_status_handle();

			//对离线设备消警点播
			warn_cancel_offline_device();
		} else {
			//报警,保存叫应记录,并推送平台
			warn_record_result_handle();
		}
	}

exit_warn:

	//DEBUG("warn thread exit");
	if(is_scan_warn_need_stop == 0) {
		warn_threadid = 0;
	}

	pthread_exit(NULL);
}

void stop_warn_thread(void)
{
	if(warn_threadid > 0) {
		DEBUG("stop_warn_thread");
		is_scan_warn_need_stop = 1;
		DEBUG("stop_warn_thread pthread_ join");
		pthread_join(warn_threadid, NULL);
		DEBUG("stop_warn_thread pthread_ join pass");
		warn_threadid = 0;
		is_scan_warn_need_stop = 0;
	}
}

void start_warn_thread(void)
{
	pthread_create(&warn_threadid, NULL, scan_warn_thread, NULL);
}

int update_warn_status(WARN_STATE_E warn_value)
{
	//if(g_warn_req == warn_value) {
		//表明当前正在执行相同报警值
		//return -1;
	//}
	
	if(warn_value == ALARM_STATE_Cancel_transfer) {
		g_cancel_time = time(NULL);			//消警时间
	} else {
		g_warn_time = time(NULL);			//报警时间
		g_warn_value = warn_value;			//报警值
	}

	g_warn_req = warn_value; 			//报警值
	g_warn_seq = generate_msgid();		//报警序列号

	return 0;
}

void warn_handler_start(void)
{	
	stop_warn_thread();
	start_warn_thread();
}

//devid转换为sn
void devid_to_sn(unsigned char *devid, char *dev_sn)
{
	int i;
	
	int val_h;
	int val_l;
	
	for(i=0; i<FRAME_REMOTER_ADDR_LEN; i++)
	{
		val_h = (devid[i] >> 4) & 0xf;
		val_l = devid[i] & 0xf;
		dev_sn[2*i] = val_h < 10 ? val_h + '0' : val_h - 10 + 'A';
		dev_sn[2*i + 1] = val_l < 10 ? val_l + '0' : val_l - 10 + 'A';
	}
}

//sn转换为devid
int sn_to_devid(const char *dev_sn, unsigned char *devid)
{
	int i;
	char str[3] = {0};

	for(i=0; i<FRAME_REMOTER_ADDR_LEN; i++)
	{
		str[0] = dev_sn[i*2];
		str[1] = dev_sn[i*2 + 1];
		devid[i] = strtoul(str, NULL, 16);
	}

	return i;
}


void sn_convert(char *to_devsn, char *from_devsn)
{
	strcpy(to_devsn, &from_devsn[3]);
}

int set_dev_node_netinfo(int gw_addr, char *dev_sn, int addr, int cellid) 
{
	int i;
	unsigned char buf[32];

	char to_devsn[32] = {0};

	if(gw_addr <= 0) {
		gw_addr = get_gw_addr();
		DEBUG("use local gw_addr=%04X", gw_addr);
	}

	if(valid_gw_addr(gw_addr) && valid_devnode_addr(addr) && valid_cellid(cellid)) {
		i=0;
		buf[i++] = (gw_addr>>8) & 0xFF;	//呼叫器地址
		buf[i++] = (gw_addr) & 0xFF;
		
		sn_convert(to_devsn, dev_sn);
		i += sn_to_devid(to_devsn, &buf[i]);
		
		buf[i++] = (addr>>8) & 0xFF;	//报警器地址
		buf[i++] = (addr) & 0xFF;
		
		buf[i++] = (cellid) & 0xFF;	//小区ID
		
		
		hydrology_transform(HYD_CMD_SET_NETINFO, buf, i);

		return 0;
	}

	return -1;
}

void dev_node_info_printf(void)
{
	int index = 0;
	DEV_NODE *dev_node, *tmp;

	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
		DEBUG("[%02d]:%s, devaddr:%04X\n", ++index, dev_node->dev_sn, dev_node->devaddr);
	}
}

void update_devnode_from_file(char *filename)
{
	cJSON *root;
	cJSON *array;
	cJSON *element;
	cJSON *devSn;	
	int dev_count = 0;
	int index;
	
	cJSON *nodeAddr;
	int dev_Addr = -1;	//报警器窄带地址

	DEV_NODE *dev_node, *tmp;

	stop_warn_thread();
	stop_scan_online_thread();

	//清空设备链表
	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
		list_del(&dev_node->node_list);
		free(dev_node);
	}

	root = parse_root_from_file(filename);
	if(root) {
		array = cJSON_GetObjectItem(root, "data");
		if(array) {
			dev_count = cJSON_GetArraySize(array);
			for(index=0; index < dev_count; index++) {
				element = cJSON_GetArrayItem(array, index);
				devSn = cJSON_GetObjectItem(element, "devSn");
				nodeAddr = cJSON_GetObjectItem(element, "devAddr");
				if(devSn) {
					if(strncmp(devSn->valuestring, "58021", 5) != 0) {
						continue;
					}
					
					dev_node = malloc(sizeof(DEV_NODE));
					memset(dev_node, 0, sizeof(DEV_NODE));
					strncpy(dev_node->dev_sn, devSn->valuestring, sizeof(dev_node->dev_sn));

					if(nodeAddr) {
						if(nodeAddr->type == cJSON_String)
							dev_Addr = strtoul(nodeAddr->valuestring, NULL, 16);
						else if(nodeAddr->type == cJSON_Number)
							dev_Addr = nodeAddr->valueint;
						
						if(valid_devnode_addr(dev_Addr)) {
							dev_node->devaddr = dev_Addr;
						}
						//DEBUG("dev_node addr: %04X", dev_Addr);
					}
					
					list_add_tail(&dev_node->node_list, get_devnode_list_head());
				}

			}
		}

		save_root_to_file(root, filename);
		
		cJSON_Delete(root);
	}	else {
		DEBUG("%s parse error", filename);
	}

	dev_node_info_printf();

	//if(dev_count > 0 && dev_count <= 10)
	//	start_scan_online_thread();
}

cJSON *cJSON_Create(char *command)
{
	cJSON *root;
	root = cJSON_CreateObject();
	cJSON_AddNumberToObject(root, "id", generate_msgid());
	cJSON_AddStringToObject(root, "gwid", get_gw_sn());
	cJSON_AddStringToObject(root, "command", command);
	return root;
}

static void devNode_online_publish_to_server(DEV_NODE *node)
{
	char *out;
	cJSON *root, *data, *element;
	char addr_str[32] = {0};
	sprintf(addr_str, "%04X", node->devaddr);
	root = cJSON_Create("status");
	cJSON_AddItemToObject(root, "data", data = cJSON_CreateArray());
	element = cJSON_CreateObject();
	cJSON_AddStringToObject(element, "devSn", node->dev_sn);
	cJSON_AddNumberToObject(element, "online", node->online);
	cJSON_AddNumberToObject(element, "battery", node->battery_level);
	cJSON_AddNumberToObject(element, "rssi", node->dev_rssi);
	cJSON_AddStringToObject(element, "addr", addr_str);
	cJSON_AddNumberToObject(element, "lte_csq", node->lte_csq);
	cJSON_AddNumberToObject(element, "ac_adapter", node->ac_adapter);
	cJSON_AddNumberToObject(element, "online_lte", node->online_lte);
	cJSON_AddNumberToObject(element, "online_tpunb", node->online_tpunb);
	cJSON_AddItemToArray(data, element);
	out = cJSON_PrintUnformatted(root);
	cJSON_Delete(root);
	gw_publish_notify_req_data(out, strlen(out));
	free(out);
}

void devNode_publish_all_to_server(void)
{
	char *out;
	cJSON *root, *data, *element;
	DEV_NODE *dev_node, *tmp;

	char addr_str[32] = {0};

	if(devnode_list_empty()) {
		return;
	}

	if(get_online_dev_num() == 0) {
		return;
	}

	root = cJSON_Create("status");
	cJSON_AddItemToObject(root, "data", data = cJSON_CreateArray());
	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
		sprintf(addr_str, "%04X", dev_node->devaddr);
		element = cJSON_CreateObject();
		cJSON_AddStringToObject(element, "devSn", dev_node->dev_sn);
		cJSON_AddStringToObject(element, "devAddr", addr_str);
		cJSON_AddNumberToObject(element, "online", dev_node->online);
		cJSON_AddNumberToObject(element, "battery", dev_node->battery_level);
		cJSON_AddNumberToObject(element, "rssi", dev_node->dev_rssi);
		cJSON_AddItemToArray(data, element);
	}

	out = cJSON_PrintUnformatted(root);
	cJSON_Delete(root);
	gw_publish_notify_req_data(out, strlen(out));
	free(out);
}

void broadcast_task_answer_update(int taskid)
{
	msgbuf_t msg = {0};
	struct qt_data_upblock *data;

	data = (struct qt_data_upblock *)&msg;;
	data->head.msgtype = MSG_CMD_UP;
	data->head.cmdtype = MSG_TYPE_BROADCAST_TASK_ANSWER;
	data->value = taskid;

	qt_msg_send(data, sizeof(struct qt_data_upblock));
}

//通知qt 设备在线
void online_state_notify_qt(char *dev_sn, int online)
{
	msgbuf_t msg = {0};
	struct qt_data_upblock *data;

	data = (struct qt_data_upblock *)&msg;;
	data->head.msgtype = MSG_CMD_UP;
	data->head.cmdtype = MSG_TYPE_ENDPOINT_STATUS;
	strncpy(data->dev_sn, dev_sn, DEVSN_LEN);
	data->value = online;

	qt_msg_send(data, sizeof(struct qt_data_upblock));
}

//上报QT设备所有状态
void dev_status_notify_qt(DEV_NODE *dev_node)
{
	msgbuf_t msg = {0};
	struct qt_data_upblock *data;

	data = (struct qt_data_upblock *)&msg;;
	data->head.msgtype = MSG_CMD_UP;
	data->head.cmdtype = MSG_TYPE_DEV_STATUS;
	
	strncpy(data->dev_sn, dev_node->dev_sn, DEVSN_LEN);
	
	data->online = dev_node->online;
	data->online_lte = dev_node->online_lte;
	data->online_tpunb = dev_node->online_tpunb;
	data->devaddr = dev_node->devaddr;
	data->battery_level = dev_node->battery_level;
	data->dev_rssi = dev_node->dev_rssi;
	data->lte_csq = dev_node->lte_csq;
	data->ac_adapter = dev_node->ac_adapter;

	qt_msg_send(data, sizeof(struct qt_data_upblock));
}

//通知qt 设备已应答
void waring_state_notify_qt(char *dev_sn, int waring)
{
	msgbuf_t msg = {0};
	struct qt_data_upblock *data;

	data = (struct qt_data_upblock *)&msg;;
	data->head.msgtype = MSG_CMD_UP;
	data->head.cmdtype = MSG_TYPE_WARNCANCEL;
	strncpy(data->dev_sn, dev_sn, DEVSN_LEN);
	data->value = waring;

	qt_msg_send(data, sizeof(struct qt_data_upblock));
}

//1级报警	2级报警	3级报警
void trigger_alarm_notify_qt(int alarm_level)
{
	msgbuf_t msg = {0};
	struct qt_data_upblock *data;

	data = (struct qt_data_upblock *)&msg;;
	data->head.msgtype = MSG_CMD_UP;
	data->head.cmdtype = MSG_TYPE_TRIGGER_ALARM;
	data->value = alarm_level;

	qt_msg_send(data, sizeof(struct qt_data_upblock));
}

//监测水位
void water_level_notify_qt(int water_level)
{
	msgbuf_t msg = {0};
	struct qt_data_upblock *data;

	data = (struct qt_data_upblock *)&msg;;
    data->head.msgtype = MSG_CMD_UP;
	data->head.cmdtype = MSG_TYPE_WATER_LEVEL;
	data->value = water_level;

	qt_msg_send(data, sizeof(struct qt_data_upblock));
}

//监测雨量
void rain_level_notify_qt(int rain_level)
{
	msgbuf_t msg = {0};
	struct qt_data_upblock *data;

	data = (struct qt_data_upblock *)&msg;;
    data->head.msgtype = MSG_CMD_UP;
	data->head.cmdtype = MSG_TYPE_RAIN_LEVEL;
	data->value = rain_level;

	qt_msg_send(data, sizeof(struct qt_data_upblock));
}

//三级预警阈值
void warn_water_notify_qt(int water_level_1, int water_level_2, int water_level_3)
{
	msgbuf_t msg = {0};
	struct qt_data_upblock *data;

	data = (struct qt_data_upblock *)&msg;;
	data->head.msgtype = MSG_CMD_UP;
	data->head.cmdtype = MSG_TYPE_WARN_WATER;
	data->water_level[0] = water_level_1;
	data->water_level[1] = water_level_2;
	data->water_level[2] = water_level_3;

	qt_msg_send(data, sizeof(struct qt_data_upblock));
}

//更新转移路线图片
void transferWaySetting_notify_qt(void)
{
	msgbuf_t msg = {0};
	struct qt_head_block *data;

	data = (struct qt_head_block *)&msg;;
	data->msgtype = MSG_CMD_UP;
	data->cmdtype = MSG_TYPE_TRANSFERWAY_SETTING;

	qt_msg_send(data, sizeof(struct qt_head_block));
}

//MQTT下发更新终端信息
void update_devnode_notify_qt(void)
{
	msgbuf_t msg = {0};
	struct qt_head_block *data;

	data = (struct qt_head_block *)&msg;;
	data->msgtype = MSG_CMD_UP;
	data->cmdtype = MSG_TYPE_UPDATE_DEVNODE_FROMFILE;

	qt_msg_send(data, sizeof(struct qt_head_block));
}

void update_devnode_info(DEV_NODE *dev_node)
{
	DEV_NODE *node, *tmp;

	//char online_sn[4096] = {0};
	//char offline_sn[4096] = {0};

	//上报MQTT服务器
	devNode_online_publish_to_server(dev_node);

	//保存设备地址,用于后期点播
	dev_addr_save_to_file(dev_node->dev_sn, dev_node->devaddr);

	list_for_each_entry_safe(node, tmp, get_devnode_list_head(), node_list) {
		if(node->online) {
			//strcat(online_sn, node->dev_sn);
			//strcat(online_sn, " ");
		} else {
			//strcat(offline_sn, node->dev_sn);
			//strcat(offline_sn, " ");
		}
	}

	//打印终端在线离线情况
	//DEBUG("online_sn: %s", online_sn);
	//DEBUG("offline_sn: %s", offline_sn);
}

static void devnode_offline_notify_qt(void)
{
	DEV_NODE *dev_node, *tmp;

	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
		if(dev_node->online_rsp == 0) {
			dev_node->online = 0;
			online_state_notify_qt(dev_node->dev_sn, 0);		//通知qt界面 设备离线
		}
	}
}

static int get_imei(char *imei)
{
	int ret;
	int len = 0;
	fd_set fds;
	struct timeval timeout;
	char *atcmd;
	char reply[512] = {0};

	if(!isFileExists("/dev/ttyUSB2")) {
		return -1;
	}

	int fd = open("/dev/ttyUSB2", O_RDWR);
	if(fd > 0) {
		atcmd = "at+cimi\r\n";
		//DEBUG("send at+cimi to ttyUSB2");
		write(fd, atcmd, strlen(atcmd));
	} else {
		DEBUG("open ttyUSB2 error");
	}

	while(1)
	{
		timeout.tv_sec = 0;
		timeout.tv_usec = 10000;
		FD_ZERO(&fds);
		FD_SET(fd, &fds);
		ret = select(fd+1, &fds, NULL, NULL, &timeout);
		if(ret == 0)
		{
			break;
		}
		else if(ret == -1)
		{
			continue;
		}
		else
		{
			len += read(fd, &reply[len], 1);
			if(len > 255)
			{
				len = 255;
			}
			else if(len > 4)
			{
				if(reply[len-4] == '\n' && reply[len-3] == '\n' && reply[len-2] == '\n' && reply[len-1] == '\n')
				{
					reply[len-4] = 0;
					//DEBUG("len=%d buf=%s", len, &reply[2]);
					strcpy(imei, &reply[2]);
					break;
				}
			}
		}
	}

	close(fd);

	return len;
}

static int get_iccid(char *iccid)
{
	int ret;
	int len = 0;
	fd_set fds;
	struct timeval timeout;
	char *atcmd;
	char reply[512] = {0};

	if(!isFileExists("/dev/ttyUSB2")) {
		return -1;
	}

	int fd = open("/dev/ttyUSB2", O_RDWR);
	if(fd > 0) {		
		atcmd = "at+qccid\r\n";
		//DEBUG("send at+qccid to ttyUSB2");
		write(fd, atcmd, strlen(atcmd));
	} else {
		DEBUG("open ttyUSB2 error");
	}

	while(1)
	{
		timeout.tv_sec = 1;
		timeout.tv_usec = 0;
		FD_ZERO(&fds);
		FD_SET(fd, &fds);
		ret = select(fd+1, &fds, NULL, NULL, &timeout);
		if(ret == 0)
		{
			break;
		}
		else if(ret == -1)
		{
			continue;
		}
		else
		{
			len += read(fd, &reply[len], 1);
			if(len > 255)
			{
				len = 255;
			}
			else if(len > 4)
			{
				if(reply[len-4] == '\n' && reply[len-3] == '\n' && reply[len-2] == '\n' && reply[len-1] == '\n')
				{
					reply[len-4] = 0;
					//DEBUG("len=%d buf=%s", len, &reply[10]);
					strcpy(iccid, &reply[10]);
					break;
				}
			}
		}
	}

	close(fd);

	return len;
}

void gw_heartBeat_to_server(void)
{
	char *out;
	cJSON *root;
	char gwaddr_str[32] = {0};
	static char iccid[64] = {0};
	static char imei[64] = {0};
	
	if(strlen(iccid) == 0) {
		get_iccid(iccid);
	}

	if(strlen(imei) == 0) {
		get_imei(imei);
	}

	sprintf(gwaddr_str, "%04X", get_gw_addr());
	root = cJSON_Create("heartBeat");
	cJSON_AddStringToObject(root, "addr", gwaddr_str);
	cJSON_AddStringToObject(root, "ver", VERSION);
	cJSON_AddStringToObject(root, "iccid", iccid);
	cJSON_AddStringToObject(root, "imei", imei);
	cJSON_AddNumberToObject(root, "cellid", get_gw_cellid());
	cJSON_AddNumberToObject(root, "group", get_gw_group());
	cJSON_AddNumberToObject(root, "lte_csq", get_signal());
	cJSON_AddNumberToObject(root, "battery", get_battery_value());
	cJSON_AddNumberToObject(root, "charge", get_adapter_connect());
	out = cJSON_PrintUnformatted(root);
	cJSON_Delete(root);
	gw_publish_notify_req_data(out, strlen(out));
	free(out);
}

int get_signal(void)
{
	int ret;
	int len = 0;
	fd_set fds;
	struct timeval timeout;
	char *atcmd;
	char reply[512] = {0};
	char *ptr;
	char *ptr_signal = NULL;

	if(!isFileExists("/dev/ttyUSB2")) {
		return -1;
	}
	
	int fd = open("/dev/ttyUSB2", O_RDWR);
	if(fd > 0) {
		atcmd = "at+csq\r\n";
		//DEBUG("send at+qccid to ttyUSB2");
		write(fd, atcmd, strlen(atcmd));
	} else {
		DEBUG("open ttyUSB2 error");
		return -1;
	}

	while(1)
	{
		timeout.tv_sec = 0;
		timeout.tv_usec = 500000;
		FD_ZERO(&fds);
		FD_SET(fd, &fds);
		ret = select(fd+1, &fds, NULL, NULL, &timeout);
		if(ret == 0)
		{
			break;
		}
		else if(ret == -1)
		{
			continue;
		}
		else
		{
			len += read(fd, &reply[len], 1);
			if(len > 255)
			{
				len = 255;
			}
			else if(len > 4)
			{
				if(reply[len-4] == '\n' && reply[len-3] == '\n' && reply[len-2] == '\n' && reply[len-1] == '\n')
				{
					reply[len-4] = 0;
					ptr_signal = strchr(reply, ' ') + 1;//+CSQ: 31,99
					if(ptr_signal) {
						ptr = strchr(ptr_signal, ',');
						if(ptr) {
							ptr[0] = 0;
						}
						//DEBUG("len=%d buf=%s", len, ptr_signal);
						break;
					}
				}
			}
		}
	}

	close(fd);

	if(ptr_signal)
	{
		return atoi(ptr_signal);
	}

	return -2;
}

//在线监测逻辑
static pthread_t online_threadid = 0;
static int is_scan_online_need_stop = 0;	//1：线程需停止

static int is_online_thread_active(void)
{
	return (is_scan_online_need_stop == 0);
}

static void online_thread_interruptable_waiting(int count)
{
	int i = 0;
	while(is_online_thread_active() && i < count) {
		++i;
		millisecond_sleep(1);
	}
}

//在线点播
static void oline_unicast(char *dev_sn, unsigned short devaddr)
{
	char to_devsn[32] = {0};
	unsigned char buf[128] = {0};
	ONLINE_REQ_DATA *online_req = (ONLINE_REQ_DATA *)buf;
	online_req->online_seq = generate_msgid();

	hydrology_param_t hydrology_param;

	//指令增加报警器SN,防止广播时同时回复
	sn_convert(to_devsn, dev_sn);
	sn_to_devid(to_devsn, online_req->remoter_addr);
	//DEBUG("%s %s", __FUNCTION__, to_devsn);

	memset(&hydrology_param, 0, sizeof(hydrology_param));
	hydrology_param.cmdtype = HYD_CMD_GET_ONLINE;
	hydrology_param.buf = online_req;
	hydrology_param.length = sizeof(ONLINE_REQ_DATA);
	hydrology_param.addr = devaddr;
	memcpy(hydrology_param.dev_sn, dev_sn, sizeof(hydrology_param.dev_sn));
	hydrology_transform_enqueue(&hydrology_param);	//devaddr > 0 点播,	devaddr == 0 广播
}

void oline_unicast_of_devSn(char *dev_sn)
{
	DEV_NODE *dev_node;
	
	dev_node = get_dev_node(dev_sn);
	if(dev_node) {
		dev_node->online_lte = 0;
		dev_node->online_tpunb = 0;
		oline_unicast(dev_node->dev_sn, dev_node->devaddr);
	} else {
		oline_unicast(dev_sn, 0);
	}
}


//在线广播
static void online_broadcast(void)
{
	hydrology_transform(HYD_CMD_GET_ONLINE, NULL, 0);
}

void dev_online_scan(char *dev_sn)
{
	DEV_NODE *dev_node;

	if(dev_sn == NULL) {
		//在线广播
		online_broadcast();
	} else {
		//在线点播
		dev_node = get_dev_node(dev_sn);
		if(dev_node) {
			dev_node->online_lte = 0;
			dev_node->online_tpunb = 0;
			oline_unicast(dev_node->dev_sn, dev_node->devaddr);
		}
	}
}

static void online_rsp_status_handle(void)
{
	int i;
	DEV_NODE *dev_node, *tmp;	

	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {

		if(is_online_thread_active() && dev_node->online_rsp == 0) {//loop_1
			//如果设备还离线 尝试点播5次是否在线
			for(i=0; is_online_thread_active() && (i < RETRY_COUNT); i++) {//loop_2

				//在线状态点播
				oline_unicast(dev_node->dev_sn, dev_node->devaddr);

				//每次等待10秒				
				online_thread_interruptable_waiting(LOOP_WAIT_TIMEOUT);
				//DEBUG("online_rsp index=%d online_rsp=%d", i, dev_node->online_rsp);

				//如果已在线、点播下一个设备
				if(dev_node->online_rsp == 1) {
					break;
				}
			}
		}
	}
}

static void online_rsp_status_clear(void)
{
	DEV_NODE *dev_node, *tmp;
	list_for_each_entry_safe(dev_node, tmp, get_devnode_list_head(), node_list) {
		dev_node->online_rsp = 0;
	}
}

static void online_finish_handle(void)
{
	if(is_online_thread_active()) {
		//更新QT界面
		devnode_offline_notify_qt();

		//通知MQTT服务器
		devNode_publish_all_offline_to_server();
	}
}

static void *scan_online_thread(void *arg)
{
	DEBUG("%s start", __FUNCTION__);
	
	if(devnode_list_empty()) {
		goto exit_thread;
	}

	//重置在线查询反馈状态
	online_rsp_status_clear();

	//广播获取在线状态
	online_broadcast();

	//等待回复
	online_thread_interruptable_waiting(LOOP_WAIT_TIMEOUT);

	//点播5次是否在线
	online_rsp_status_handle();

	//在线结果处理
	online_finish_handle();

exit_thread:

	DEBUG("%s exit", __FUNCTION__);
	if(is_scan_online_need_stop == 0) {
		online_threadid = 0;
	}

	pthread_exit(NULL);
}

void stop_scan_online_thread(void)
{
	if(online_threadid > 0) {
		is_scan_online_need_stop = 1;
		DEBUG("start_scan_online_thread pthread_ join");
		pthread_join(online_threadid, NULL);
		DEBUG("start_scan_online_thread pthread_ join pass");
		online_threadid = 0;
		is_scan_online_need_stop = 0;
	}
}

void start_scan_online_thread(void)
{
	stop_scan_online_thread();
	pthread_create(&online_threadid, NULL, scan_online_thread, NULL);
}

static int need_scan_online_status(void)
{
	static int flag = 0;
	int cur_minute = 0;

	//整点0分钟获取在线状态
	cur_minute = get_current_minute();
	if(cur_minute == 0) {
		if(flag == 0) {
			flag = 1;
			return 1;
		}
	} else {
		flag = 0;
	}

	return 0;
}

static void online_detect_handler(void)
{
	if(need_scan_online_status()) {
		start_scan_online_thread();
	}
}

void start_qt_ui(void)
{
	//DEBUG("start qt ui restart");
	//system("/oem/init.d/S99ControlTerminal restart");
}

static void gpio_init(void)
{
	//使能喇叭电源
	gpio_export(SPEAKER_POWER_PIN);
	gpio_direction_out(SPEAKER_POWER_PIN);
	gpio_value_output(SPEAKER_POWER_PIN, 1);

	//停止充电
	gpio_export(BATTERY_CHARGING_PIN);
	gpio_direction_out(BATTERY_CHARGING_PIN);
	gpio_value_output(BATTERY_CHARGING_PIN, 0);

	//电池充电检测
	gpio_export(BATTERY_CHARGE_DETEC_PIN);
	gpio_direction_in(BATTERY_CHARGE_DETEC_PIN);

	//适配器检测引脚配置为输入
	gpio_export(ADAPTER_DETEC_PIN);
	gpio_direction_in(ADAPTER_DETEC_PIN);
}

//获取电池充电状态：1:满电 0:充电中
int get_battery_charge_state(void)
{
	return get_gpio_value(BATTERY_CHARGE_DETEC_PIN);
}

//获取电池电量
int get_battery_value(void)
{
	int fd;
	char buf[128] = {0};
	char file[128] = {0};
	int in_voltage1_raw = 0;
	float in_voltage_scale = 0;

	sprintf(file, "/sys/bus/iio/devices/iio:device0/in_voltage2_raw");

	fd = open(file, O_RDONLY);
	if(fd > 0) {
		memset(buf, 0, sizeof(buf));
		read(fd, buf, sizeof(buf));
		close(fd);
		in_voltage1_raw = atoi(buf);
	}

	sprintf(file, "/sys/bus/iio/devices/iio:device0/in_voltage_scale");
	fd = open(file, O_RDONLY);
	if(fd > 0) {
		memset(buf, 0, sizeof(buf));
		read(fd, buf, sizeof(buf));
		close(fd);
		in_voltage_scale = atof(buf);
	}

    float volt = (in_voltage1_raw / 1024.0f) * 8.4f * (1.8f / in_voltage_scale);

    // 电压范围定义：8.4V对应100%，6.1V对应0%
    const float MAX_VOLTAGE = 8.4f;  // 满电电压
    const float MIN_VOLTAGE = 6.1f;  // 空电电压
    
    // 根据电压计算电量百分比
    int percent = (int)(((volt - MIN_VOLTAGE) / (MAX_VOLTAGE - MIN_VOLTAGE)) * 100);
    
    // 限制范围在0-100之间
    if (percent < 0) percent = 0;
    if (percent > 100) percent = 100;

	return percent;
}

//设置屏幕背光亮度	0-255
void set_backlight_brightness(int brightness)
{
	char buf[128] = {0};
	char file[128] = {0};

	sprintf(file, "/sys/class/backlight/backlight/brightness");
	int fd = open(file, O_WRONLY);
	if(fd > 0) {
		sprintf(buf, "%d", brightness);
		write(fd, buf, strlen(buf));
		close(fd);
	}
}

//适配器已接入 1:接入	0:未接
int get_adapter_connect(void)
{
	return (get_gpio_value(ADAPTER_DETEC_PIN) == 0) ? 1 : 0;
}

static void charge_enable_opr(int enable)
{
	char buf[128] = {0};
	char file[128] = {0};

	sprintf(file, "/sys/class/leds/charge_ctrl/brightness");
	int fd = open(file, O_WRONLY);
	if(fd > 0) {
		sprintf(buf, "%d", enable);
		write(fd, buf, strlen(buf));
		close(fd);
	}
}

//检测电源适配器是否接入,是则使能电池充电
static void charge_enable_detect(void)
{
	int value;
	static int charge_enable = 0;

	value = get_adapter_connect();
	//DEBUG("%d %d", value, charge_enable);
	if(value == 1 && charge_enable == 0) {
		charge_enable = 1;
		gpio_value_output(BATTERY_CHARGING_PIN, 1);//使能电池充电
		charge_enable_opr(1);//新内核
	} else if(value == 0 && charge_enable == 1) {
		charge_enable = 0;
		gpio_value_output(BATTERY_CHARGING_PIN, 0);//关闭电池充电
		charge_enable_opr(0);//新内核
	}
}

//QT界面查询所有状态
void get_all_status_info(void)
{
	msgbuf_t msg = {0};
	struct qt_data_upblock *data;

	data = (struct qt_data_upblock *)&msg;;
	data->head.msgtype = MSG_CMD_UP;
	data->head.cmdtype = MSG_TYPE_GW_STATUS;

	//窄带
	unsigned short tpunb_ok = is_tpunb_ok();
	//DEBUG("tpunb_ok:%d", tpunb_ok);

	//4G
	static char imei[24] = {0};
	static char iccid[24] = {0};
	unsigned short lte_csq;
	char ip[24] = {0};

	if(strlen(imei) == 0) 
		get_imei(imei);

	if(strlen(imei) > 0 && strlen(iccid) == 0) 
		get_iccid(iccid);

	if(strlen(iccid) > 0) {
		lte_csq = get_signal();
		get_eth_ip("usb0", ip);
		//DEBUG("imei:%s", imei);
		//DEBUG("iccid:%s", iccid);
		//DEBUG("lte_csq:%d", lte_csq);
		//DEBUG("ip:%s", ip);
	}

	//MQTT
	unsigned short mqtt_connect_status = mqtt_client_connect_ok();;
	//DEBUG("mqtt_connect_status:%d", mqtt_connect_status);

	//电源适配器
	unsigned short ac_adapter = get_adapter_connect();

	//电池电量
	unsigned short battery_level = get_battery_value();

	//是否满电
	unsigned short is_full_battery = get_battery_charge_state();
	//DEBUG("ac_adapter:%d", ac_adapter);
	//DEBUG("battery_level:%d", battery_level);
	//DEBUG("is_full_battery:%d", is_full_battery);

	//网关SN,窄带地址,小区ID
	char gw_devSn[32] = {0};
	get_gw_devSn(gw_devSn);
	unsigned short gw_devAddr = get_gw_addr();
	unsigned char gw_devCellid = get_gw_cellid();
	//DEBUG("gw_devSn:%s", gw_devSn);
	//DEBUG("gw_devAddr:%04X", gw_devAddr);
	//DEBUG("gw_devCellid:%d", gw_devCellid);

	strcpy(data->dev_sn, gw_devSn);
	data->devaddr = gw_devAddr;
	data->gw_devCellid = gw_devCellid;
	data->is_full_battery = is_full_battery;
	data->battery_level = battery_level;
	data->ac_adapter = ac_adapter;
	data->mqtt_connect_status = mqtt_connect_status;
	data->tpunb_ok = tpunb_ok;
	strcpy(data->imei, imei);
	strcpy(data->iccid, iccid);
	data->lte_csq = lte_csq;
	strcpy(data->ip, ip);
	strcpy(data->version, VERSION);

	qt_msg_send(data, sizeof(struct qt_data_upblock));
}

//static void wake_up_from_sleep_mode_handler(void)
//{
	//if(isFileExists(SLEEP_MODE_FILE)) {
	//	remove(SLEEP_MODE_FILE);
	//	mqtt_client_reconnect();
	//}
//}

static void *dev_manage_handler(void *arg)
{
	int heartBeatCount = 1;

	gpio_init();

	dev_node_init();

	water_alarm_info_parse(WATER_LEVEL_FILE);

	update_devnode_from_file(DEV_NODE_FILE);
	
	mqtt_client_init();

	firmware_ota_init();

	while(1) {
		if((heartBeatCount % 3600) == 0) {
			gw_heartBeat_to_server();
		}

		online_detect_handler();

		charge_enable_detect();

		second_sleep(1);
		heartBeatCount++;
	}
	
	return NULL;
}

int upload_to_server(char *filename, char *out_url)
{
	int ret;
	char command[2048] = {0};
	char result[2048] = {0};
	int line = 10;

	cJSON *root;
	cJSON *value;

	sprintf(command, "curl -k --connect-timeout 300 --max-time 300 --location 'https://www.juemingt.com:19093/api/uploadImg/up' --form 'userName=\"juemingt2025\"' --form 'password=\"juemingt@_2025\"' --form 'file=@\"%s\"'", filename);
	DEBUG("%s", filename);
	DEBUG("%s", command);
	ret = myexec(command, result, &line);
	if (WIFEXITED(ret) && WEXITSTATUS(ret) == 0) {
		DEBUG("%s", result);
		//{"code":200,"success":true,"data":"https://www.juemingt.com:19093/static/juemingUp/397dd7c0-3e07-4335-8985-cc5ed2247710/alsound_test","msg":"操作成功"}
		root = cJSON_Parse(result);
		if(root) {
			value = cJSON_GetObjectItem(root, "code");
			if(value->valueint == 200) {
				//上传成功
				value = cJSON_GetObjectItem(root, "data");
				if(value) {
					strcpy(out_url, value->valuestring);
					DEBUG("upload_to_server out_url:%s", out_url);
					return 0;
				}
			}
		}
	} else {
		DEBUG("curl fail");
	}

	return -1;
}

void broadcast_task_set_answer(int taskid, char *devSn)
{
	cJSON *root;
	cJSON *value;
	char broadcast_file[128] = {0};
	sprintf(broadcast_file, "%s/task_%d.json",  BROADCAST_TASK_PATH, taskid);

	root = parse_root_from_file(broadcast_file);
	if(root) {
		value = cJSON_GetObjectItem(root, devSn);
		if(value) {
			cJSON_ReplaceItemInObject(root, devSn, cJSON_CreateNumber(1));	//1：已应答
		} else {
			cJSON_AddNumberToObject(root, devSn, 1);	//1：已应答
		}
	
		save_root_to_file(root, broadcast_file);
		cJSON_Delete(root);
	}
}

static int send_broadcast_task(struct qt_data_downblock *data)
{
	cJSON *root;
	cJSON *value;
	char out_url[1024] = {0};
	char *filepath = NULL;
	char md5sum[256] = {0};

	unsigned char buf[1024] = {0};
	BROADCASTTASK_REQ_DATA *broadcasttask_req_data = (BROADCASTTASK_REQ_DATA *)buf;

	int taskid = data->value;
	int command = data->command;

	char broadcast_file[128] = {0};
	sprintf(broadcast_file, "%s/task_%d.json",  BROADCAST_TASK_PATH, taskid);
	DEBUG("%s", broadcast_file);

	root = parse_root_from_file(broadcast_file);
	if(root) {
		value = cJSON_GetObjectItem(root, "filepath");
		if(value) {
			filepath = value->valuestring;
			DEBUG("%s", filepath);

			value = cJSON_GetObjectItem(root, "url");
			if(value == NULL) {
			//if(value == NULL || taskid == 4) {
				DEBUG("url null taskid=%d", taskid);
				if(upload_to_server(filepath, out_url) == 0) {
					if(value == NULL)
						cJSON_AddStringToObject(root, "url", out_url);							//新增
					else
						cJSON_ReplaceItemInObject(root, "url", cJSON_CreateString(out_url));	//替换

					save_root_to_file(root, broadcast_file);
				} else {
					goto err_exit;
				}
			} else {
				strcpy(out_url, value->valuestring);
			}

			strncpy(broadcasttask_req_data->url, out_url, sizeof(broadcasttask_req_data->url));
			get_file_md5sum(filepath, md5sum);
			strncpy(broadcasttask_req_data->md5sum, md5sum, sizeof(broadcasttask_req_data->md5sum));

			DEBUG("%s", md5sum);
			DEBUG("%s", filepath);
			DEBUG("%s", out_url);
		}
		DEBUG("taskid=%d", taskid);

		broadcasttask_req_data->broadcastTaskId = taskid;
		value = cJSON_GetObjectItem(root, "broadcast_type");
		broadcasttask_req_data->broadcastType = value->valueint;
		broadcasttask_req_data->command = command;

		if(command == 1) {
			if(strlen(out_url) > 0) {
				hydrology_transform(HYD_CMD_BROADCAST_TASK, (unsigned char *)(broadcasttask_req_data), sizeof(BROADCASTTASK_REQ_DATA));
			}
		} else {
			hydrology_transform(HYD_CMD_BROADCAST_TASK, (unsigned char *)(broadcasttask_req_data), offsetof(BROADCASTTASK_REQ_DATA, md5sum));
		}
	}

err_exit:
	cJSON_Delete(root);
	return 0;
}

void handle_broadcast_task(struct qt_data_downblock *data)
{
	unsigned char buf[1024] = {0};
	BROADCASTTASK_REQ_DATA *broadcasttask_req_data = (BROADCASTTASK_REQ_DATA *)buf;

	broadcasttask_req_data->broadcastTaskId = data->value;
	broadcasttask_req_data->broadcastType = data->broadcast_type;
	broadcasttask_req_data->command = data->command;

	hydrology_transform(HYD_CMD_BROADCAST_TASK, (unsigned char *)(broadcasttask_req_data), offsetof(BROADCASTTASK_REQ_DATA, md5sum));
}

void start_broadcast_task(struct qt_data_downblock *data)
{
	struct qt_data_downblock *qtMsg = malloc(sizeof(struct qt_data_downblock));
	memcpy(qtMsg, data, sizeof(struct qt_data_downblock));
	create_thread(send_broadcast_task_thread, qtMsg);
}

void *send_broadcast_task_thread(void *arg)
{
	struct qt_data_downblock *data = (struct qt_data_downblock *)arg;
	second_sleep(1);
	send_broadcast_task(data);
	free(data);
	return NULL;
}

int devnode_manage_init(void)
{
	create_thread(dev_manage_handler, NULL);
	return 0;
}

